// Dynamic tree editor - tree-like data structures editor for .NET/Mono.
// Copyright (C) 2006  Vladimir Sibirov
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

using System;
using System.Data;

namespace TreeEditor
{
	/// <summary>
	/// This class represents the data column for the concreet node class.
	/// Actually, it's a DataColumn class wrapper to match the incapsulation principle.
	/// </summary>
	public class Column
	{
		/// <summary>
		/// Unique column name.
		/// </summary>
		private string name;

		/// <summary>
		/// Aggregated DataColumn.
		/// </summary>
		private DataColumn contents;

		/// <summary>
		/// A class this column belongs to.
		/// </summary>
		private Class container;

		/// <summary>
		/// The dataset.
		/// </summary>
		private DataSet data;

		/// <summary>
		/// Whether it's a non-registered column.
		/// </summary>
		private bool isNew = false;

		/// <summary>
		/// Instance constructor.
		/// </summary>
		/// <param name="colName">Column name.</param>
		/// <param name="colContainer">Container Class object.</param>
		public Column(string colName, Class colContainer)
		{
			this.container = colContainer;
			data = container.ParentTree.Data;
			// Perform a check whether such column already exists in a container class.
			if(container.Columns[colName] != null)
			{
				// Loading a column existing in class
				Copy((Column) container.Columns[colName]);
				isNew = false;
			}
			else if(data.Tables[container.Name] != null && data.Tables[container.Name].Columns.IndexOf(colName) > 0)
			{
				// Loading a column from dataset
				contents = data.Tables[container.Name].Columns[colName];
				isNew = false;
			}
			else
			{
				// Creating a new column
				contents = new DataColumn(colName);
				contents.Caption = colName;
				isNew = true;
			}
			this.name = colName;
		}

		/// <summary>
		/// Unique column name.
		/// </summary>
		public string Name
		{
			get
			{
				return name;
			}
			set
			{
				// Check if such column is already in class
				if(container.Columns[value] == null)
				{
					if(!isNew)
					{
						// Change the existing params
						container.Columns.Remove(name);
						container.Columns.Add(value, (object) this);
						contents.ColumnName = value;
					}
					name = value;
				}
			}
		}

		/// <summary>
		/// Whether the column can contain empty values.
		/// </summary>
		public bool AllowNull
		{
			get
			{
				return contents.AllowDBNull;
			}
			set
			{
				contents.AllowDBNull = value;
			}
		}

		/// <summary>
		/// Whether the column should automatically increment its value.
		/// </summary>
		public bool AutoIncrement
		{
			get
			{
				return contents.AutoIncrement;
			}
			set
			{
				contents.AutoIncrement = value;
			}
		}

		/// <summary>
		/// Initial value for AutoIncrement.
		/// </summary>
		public long AutoIncrementStart
		{
			get
			{
				return contents.AutoIncrementSeed;
			}
			set
			{
				contents.AutoIncrementSeed = value;
			}
		}

		/// <summary>
		/// AutoIncrement step added on each insertion.
		/// </summary>
		public long AutoIncrementStep
		{
			get
			{
				return contents.AutoIncrementStep;
			}
			set
			{
				contents.AutoIncrementStep = value;
			}
		}

		/// <summary>
		/// Caption publically displayed in the application interface. Defaults to the column name.
		/// </summary>
		public string Caption
		{
			get
			{
				return contents.Caption;
			}
			set
			{
				contents.Caption = value;
			}
		}

		/// <summary>
		/// System.Type of the column contents.
		/// </summary>
		public Type DataType
		{
			get
			{
				return contents.DataType;
			}
			set
			{
				contents.DataType = value;
			}
		}

		/// <summary>
		/// Default value for this column.
		/// </summary>
		public Object DefaultValue
		{
			get
			{
				return contents.DefaultValue;
			}
			set
			{
				contents.DefaultValue = value;
			}
		}

		/// <summary>
		/// Value filter string.
		/// </summary>
		public string Filter
		{
			get
			{
				return contents.Expression;
			}
			set
			{
				contents.Expression = value;
			}
		}

		/// <summary>
		/// Column index in the class.
		/// </summary>
		public int Index
		{
			get
			{
				return contents.Ordinal;
			}
		}

		/// <summary>
		/// Maximal length of a text field.
		/// </summary>
		public int MaxLength
		{
			get
			{
				return contents.MaxLength;
			}
			set
			{
				if(this.contents.DataType == typeof(string))
					contents.MaxLength = value;
			}
		}

		/// <summary>
		/// Whether the field value can be modified after insertion.
		/// </summary>
		public bool ReadOnly
		{
			get
			{
				return contents.ReadOnly;
			}
			set
			{
				contents.ReadOnly = value;
			}
		}

		/// <summary>
		/// Whether the value must be unique in the table.
		/// </summary>
		public bool Unique
		{
			get
			{
				return contents.Unique;
			}
			set
			{
				contents.Unique = value;
			}
		}

		/// <summary>
		/// A class this column belongs to.
		/// </summary>
		public Class ParentClass
		{
			get
			{
				return container;
			}
		}


		/// <summary>
		/// Registers the column in the class.
		/// </summary>
		/// <returns>True on success, false on error.</returns>
		public bool Add()
		{
			if(isNew)
			{
				if(container.Columns[name] == null)
					container.Columns.Add(name, (object) this);
				data.Tables[container.Name].Columns.Add(contents);
				isNew = false;
				container.ParentTree.Modified = true;
				return true;
			}
			else
				return false;
		}

		/// <summary>
		/// Removes the column from the class.
		/// </summary>
		/// <returns>True on success, false on error.</returns>
		public bool Remove()
		{
			if(!isNew && data.Tables[container.Name].Columns.CanRemove(contents))
			{
				container.Columns.Remove(name);
				data.Tables[container.Name].Columns.Remove(name);
				container.ParentTree.Modified = true;
				return true;
			}
			else
				return false;
		}

		/// <summary>
		/// Commits the changes made to this column.
		/// </summary>
		/// <returns>True on success, false on error.</returns>
		public bool Update()
		{
			if(!isNew)
			{
				data.Tables[container.Name].AcceptChanges();
				container.ParentTree.Modified = true;
				return true;
			}
			else
				return false;
		}

		/// <summary>
		/// Copies another column properties.
		/// </summary>
		/// <param name="proto">Prototype column.</param>
		public void Inherit(Column proto)
		{
			// Just copy the DataColumn properties
			contents.AllowDBNull = proto.contents.AllowDBNull;
			contents.AutoIncrement = proto.contents.AutoIncrement;
			contents.AutoIncrementSeed = proto.contents.AutoIncrementSeed;
			contents.AutoIncrementStep = proto.contents.AutoIncrementStep;
			contents.Caption = proto.contents.Caption;
			contents.DataType = proto.contents.DataType;
			contents.DefaultValue = proto.contents.DefaultValue;
			contents.Expression = proto.contents.Expression;
			contents.MaxLength = proto.contents.MaxLength;
			//contents.Ordinal = proto.contents.Ordinal;
			contents.ReadOnly = proto.contents.ReadOnly;
			contents.Unique = proto.contents.Unique;
		}
		
		/// <summary>
		/// Turns this column into the link to existing one.
		/// </summary>
		/// <param name="proto">Original column.</param>
		public void Copy(Column proto)
		{
			// Copy both DataColumn properties and Column fields
			this.name = proto.name;
			this.contents = proto.contents;
			this.data = proto.data;
			this.container = proto.container;
			this.isNew = proto.isNew;
		}
	}
}
